<template>
  <div class="chat-container">
    <el-row :gutter="20">
      <!-- 在线用户列表 -->
      <el-col :span="6">
        <el-card class="box-card">
          <div slot="header" class="clearfix">
            <span>在线用户({{ onlineCount }})</span>
          </div>
          <el-scrollbar style="height: 36rem">
            <div v-for="(value, key) in onlineUsers" :key="key">
              <el-badge :value="messageCounts[value.userId]" v-if="key != id">
                <el-button class="user-item" @click="handleUserClick(value)">
                  <el-avatar :src="downloadFile(value.avatarId)" class="avatar"></el-avatar>
                  <span class="user-name">{{ value.userName }}</span>
                </el-button>
              </el-badge>
            </div>
          </el-scrollbar>
        </el-card>
      </el-col>
      <!-- 聊天窗口 -->
      <el-col :span="18" v-if="'userId' in currentToUser">
        <el-card class="box-card" shadow="hover">
          <div slot="header" class="clearfix">
            <span>{{ currentToUser.userName }}</span>
          </div>
          <el-scrollbar class="chat-window" ref="scrollMessage">
            <el-link type="primary" class="message-more" v-if="total - current * size > 0" href="#" @click.native="moreMessage(true)"
              >剩余{{ total - current * size }}条消息</el-link
            >
            <div v-for="message in messages" :key="message.id" class="message-item">
              <div class="message-content">
                <el-avatar
                  :src="downloadFile(onlineUsers[message.from].avatarId)"
                  :class="['message-avatar', `message-avatar-${id == message.from ? 'from' : 'to'}`]"></el-avatar>
                <div v-if="message.type == 2" shadow="hover" :class="['message-text', `message-text-${id == message.from ? 'from' : 'to'}`]">
                  {{ message.content }}
                </div>
                <div v-else-if="message.type == 3 || message.type == 9" :class="['message-btn', `message-btn-${id == message.from ? 'from' : 'to'}`]">
                  <el-button icon="el-icon-video-camera" @click="call" :type="id == message.from ? 'success' : 'primary'">{{
                    message.type == 3 ? '发起视频通话' : `通话结束${message.content}`
                  }}</el-button>
                </div>
                <!-- 图片消息 -->
                <image-preview
                  v-else-if="message.type == 10"
                  :src="downloadFile(message.content)"
                  :class="['message-image', `message-image-${id == message.from ? 'from' : 'to'}`]"></image-preview>
              </div>

              <div :class="['message-time', `message-time-${id == message.from ? 'from' : 'to'}`]">{{ message.createTime }}</div>
            </div>
          </el-scrollbar>
          <el-row :gutter="24" class="input-area">
            <el-col :span="2"> </el-col>
            <el-col :span="18">
              <el-input
                ref="messageInput"
                @keyup.enter.native="sendMessage(inputMessage, 2)"
                @blur="inputBlur"
                :rows="2"
                clearable
                v-model="inputMessage">
                <el-popover placement="top-start" width="350" trigger="click" slot="prepend">
                  <VEmojiPicker v-show="true" @select="selectEmoji" />
                  <el-button slot="reference">
                    <span class="icon smart-icons smart-village-biaoqing"></span>
                  </el-button>
                </el-popover>
                <div slot="append">
                  <el-button icon="el-icon-s-promotion" @click="sendMessage(inputMessage, 2)"></el-button>
                  <el-button icon="el-icon-video-camera" @click="call"></el-button>
                  <el-upload
                    ref="upload"
                    class="upload_file"
                    action="#"
                    list-type="picture"
                    :file-list="fileList"
                    :limit="1"
                    :on-progress="uploadFile"
                    :accept="'.jpg,.png,.jpeg'"
                    :auto-upload="true">
                    <el-button icon="el-icon-upload">发送文件</el-button>
                  </el-upload>
                </div>
              </el-input>
            </el-col>
          </el-row>
        </el-card>
      </el-col>
    </el-row>
    <el-dialog
      center
      :title="calling ? `通话时间:${currentTime}` : '请求视频通话'"
      :show-close="false"
      :visible.sync="videoDialog"
      width="80%"
      class="video-dialog">
      <template>
        <div><video ref="localVideo" class="local-video" autoplay></video> <video ref="remoteVideo" class="remote-video" autoplay></video></div>
        <div slot="footer">
          <el-button icon="el-icon-phone" type="success" class="accept-video" @click="acceptVideo" circle></el-button>
          <el-button icon="el-icon-close" type="danger" class="reject-video" circle @click="close(true)"></el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script>
import { mapGetters } from 'vuex'
import { VEmojiPicker } from 'v-emoji-picker'
import { downloadFile } from '@/utils/file'
import ImagePreview from '@/components/ImagePreview'

export default {
  components: {
    VEmojiPicker,
    ImagePreview,
  },
  data() {
    return {
      // 搜索用户名
      searchUsername: '',
      // 聊天记录
      messages: [],
      // 输入框
      inputMessage: '',
      // 当前聊天对象
      currentToUser: {},
      // 表情
      emoji: '',
      // 显示表情弹窗
      showEmojiDialog: false,
      // 光标位置
      selectionStart: 0,
      // 光标位置
      selectionEnd: 0,
      //查询条件
      selectForm: {
        current: 1,
        size: 10,
      },
      // 视频通话
      videoDialog: false,
      // 本地流
      localSteam: {},
      // 分页
      current: 1,
      // 页长
      size: 20,
      //总数
      total: 0,
      // 计时器
      flag: null,
      // 通话时间
      time: '00:00:00',
      // 当前时间
      currentTime: '',
      // 通话中
      calling: false,
      //文件列表
      fileList: [],
    }
  },
  computed: {
    ...mapGetters(['id']),
    // 在线用户
    onlineUsers() {
      return this.$store.state.message.onlineUsers
    },
    // 在线人数
    onlineCount() {
      return this.$store.state.message.onlineCount
    },
    // 未读消息
    messageCounts() {
      return this.$store.state.message.messageCounts
    },
  },
  mounted() {
    this.initWebsocket()
  },
  methods: {
    // 初始化socket
    initWebsocket() {
      this.$store.dispatch('message/initSocket', this.acceptMessage, this.exception)
    },
    //接收消息
    acceptMessage(e) {
      if (!e.data) {
        return
      }
      let data = JSON.parse(e.data)
      switch (data.type) {
        //用户加入
        case 1:
          //修复刷新后用户列表不更新bug
          this.$store.commit('message/SET_ONLINE_USERS', data.content)
          this.$store.commit('message/SET_ONLINE_COUNT', Object.keys(data.content).length)
          break
        //对话消息
        case 2:
          this.messages.push(data)
          this.$store.commit('message/SET_MESSAGE_COUNTS', data.from)
          this.scrollToBottom()
          break
        //收到邀请
        case 3:
          this.currentToUser = this.onlineUsers[data.from]
          this.videoDialog = true
          this.calling = false
          break
        //接收邀请
        case 4:
          this.$store.dispatch('message/requestVideo', this.currentToUser.userId)
          break
        //offer阶段
        case 5:
          this.$store
            .dispatch('message/offer', {
              localVideo: this.$refs.localVideo,
              remoteVideo: this.$refs.remoteVideo,
              to: this.currentToUser.userId,
            })
            .then((response) => {
              console.log(`offer`, response)
            })
          break
        //answer阶段
        case 6:
          this.$store
            .dispatch('message/answer', {
              localVideo: this.$refs.localVideo,
              remoteVideo: this.$refs.remoteVideo,
              offer: data.content,
              to: this.currentToUser.userId,
            })
            .then((response) => {
              console.log(`answer`, response)
            })
          break
        //设置answer
        case 7:
          this.$store.dispatch('message/localSetAnswer', data.content)
          break
        //设置candidate
        case 8:
          this.$store.dispatch('message/candidate', { candidate: data.content.candidate })
          this.start()
          this.calling = true
          break
        //拒绝&结束通话
        case 9:
          this.close(false)
          break
        //文件消息
        case 10:
          this.messages.push(data)
          this.scrollToBottom()
          break
      }
    },
    //获取焦点
    inputBlur(e) {
      this.selectionStart = e.srcElement.selectionStart
      this.selectionEnd = e.srcElement.selectionEnd
    },
    //点击用户
    handleUserClick(user) {
      this.currentToUser = user
      this.current = 1
      this.moreMessage(false)
      this.$store.commit('message/RESET_MESSAGE_COUNTS', user.userId)
    },
    //添加表情
    selectEmoji(emoji) {
      this.inputMessage = this.inputMessage.slice(0, this.selectionStart) + emoji.data + this.inputMessage.slice(this.selectionEnd)
      input.focus()
    },
    //异常处理
    exception(e) {
      console.log(e)
    },
    //点击显示更多消息
    moreMessage(more) {
      this.current = more ? this.current + 1 : 1
      this.$store
        .dispatch('message/getMessageList', {
          to: this.currentToUser.userId,
          me: this.id,
          page: this.current,
          size: this.size,
        })
        .then((response) => {
          this.messages = more ? [...response.data, ...this.messages] : response.data
          this.total = response.other.pageSize
          if (!more) {
            this.scrollToBottom()
          }
        })
    },
    //发送消息
    sendMessage(message, type) {
      var newMsg = {
        to: this.currentToUser.userId,
        type: type,
        from: this.id,
        content: message,
      }
      this.$store.dispatch('message/sendMessage', newMsg).then((response) => {
        if (response.success) {
          this.messages.push(newMsg)
          this.scrollToBottom()
        }
      })
      this.inputMessage = ''
    },
    // 下载文件
    downloadFile,
    // 滚动到底部
    scrollToBottom() {
      var scroll = this.$refs.scrollMessage
      if (!scroll) {
        return
      }
      this.$nextTick(function () {
        scroll.wrap.scrollTop = scroll.wrap.scrollHeight
      })
    },
    // 视频通话
    call() {
      this.calling = false
      this.videoDialog = true
      this.sendMessage('', 3)
    },
    // 结束通话
    close(send) {
      this.$store.dispatch('message/close', this.$refs.localVideo).then(() => {
        this.videoDialog = false
        if (send) {
          this.sendMessage(this.time, 9)
        }
      })
      this.time = this.currentTime
      this.reset()
    },
    //接受呼叫
    acceptVideo() {
      // console.log(1)
      this.sendMessage('', 4)
    },
    //开始计时
    start() {
      var second = 0
      var minute = 0
      var hour = 0
      this.flag = setInterval(() => {
        second++
        if (second >= 60) {
          second = 0
          minute++
        }

        if (minute >= 60) {
          minute = 0
          hour++
        }
        this.currentTime = this.fillZero(hour) + ':' + this.fillZero(minute) + ':' + this.fillZero(second)
      }, 1000)
    },
    //重新计时
    reset() {
      window.clearInterval(this.flag)
      this.hour = 0
      this.minute = 0
      this.second = 0
      this.currentTime = '00:00:00'
    },
    //暂停计时
    end() {
      this.flag = clearInterval(this.flag)
    },
    //补零
    fillZero(n) {
      return n < 10 ? '0' + n : n
    },
    // 上传文件
    uploadFile(event, file, fileList) {
      if (file == null) {
        return
      }
      this.$store.dispatch('file/uploadFile', file).then((response) => {
        if (response.success) {
          this.sendMessage(response.data, 10)
        }
      })
    },
  },
}
</script>

<style scoped lang="scss">
@mixin triangle($direction, $size) {
  content: '';
  position: absolute;
  width: 0;
  height: 0;
  top: 0;
  border: $size * 1.3 solid;
  @if $direction == 'right' {
    border-color: transparent transparent transparent #67c23a;
    right: $size * (-2);
  }
  @if $direction == 'left' {
    border-color: transparent #409eff transparent transparent;
    left: $size * (-2);
  }
}

.chat-container {
  padding: 20px;
}
.el-badge {
  margin-top: 0.5rem;
  width: 90%;
}
.user-item {
  width: 100%;
  height: 4rem;
  line-height: 2rem;
  .avatar {
    float: left;
    margin-right: 2rem;
  }
  .user-name {
    color: gray;
  }
}
.chat-window {
  height: 31rem;
  border-bottom: 1px solid #eee;
  scroll-behavior: smooth;

  .message-more {
    text-align: center;
    width: 100%;
  }
  .message-item {
    width: 100%;
    height: fit-content;
    overflow: auto;
    margin: 2rem 0 2rem 0;
    // height: 10rem;
    .message-content {
      width: 100%;
      overflow: auto;
      .message-image {
        max-width: 60%;
        &-from {
          float: right;
        }
        &-to {
          float: left;
        }
      }
      .message-btn {
        position: relative;
        &-to {
          float: left;
          margin-left: 1rem;
          &::before {
            @include triangle('left', 1rem);
          }
        }
        &-from {
          float: right;
          margin-right: 1rem;
          &::before {
            @include triangle('right', 1rem);
          }
        }
      }
      .message-text {
        position: relative;
        border: 1px solid #dcdfe6;
        border-radius: 4px;
        max-width: 50%;
        line-height: 2;
        word-break: break-all;
        height: fit-content;
        padding: 0.5rem 1rem 0.5rem 1rem;
        &-from {
          float: right;
          background-color: #67c23a;
          color: white;
          margin-right: 1rem;
          &::before {
            @include triangle('right', 1rem);
          }
        }
        &-to {
          float: left;
          margin-left: 1rem;
          color: white;
          background-color: #409eff;
          &::before {
            @include triangle('left', 1rem);
          }
        }
      }
      .message-avatar {
        width: 3rem;
        height: 3rem;
        &-from {
          float: right;
        }
        &-to {
          float: left;
        }
      }
    }
    .message-time {
      // margin-top: 0.5rem;
      width: 100%;
      height: fit-content;
      // border: 1px solid greenyellow;
      font-size: 0.8rem;
      color: gray;
      &-from {
        text-align: right;
        padding-right: 4rem;
      }
      &-to {
        text-align: left;
        padding-left: 4rem;
      }
    }
  }
}
.input-area {
  padding: 10px;
}

::v-deep .video-dialog {
  .accept-video,
  .reject-video {
    position: relative;
    z-index: 2;
  }

  .remote-video {
    width: 80%;
    height: 40rem;
    // border: 1px red solid;
    float: left;
  }
  .local-video {
    width: 20%;
    height: 40rem;
    // border: 1px red solid;
    float: left;
  }
}
</style>
